package org.geppeto.eva.synchronizer;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.geppeto.eva.eventory.Repository;

//import org.json.JSONArray;
import java.lang.String;
import java.net.URLDecoder;
import java.io.IOException;
import java.util.Hashtable;
import java.util.UUID;

/**
 * @author Miroslav Popovic, popovic.miroslav@gmail.com
 * 
 */
public class SyncREST extends HttpServlet {
	
	public static String PATH_MEETUP_SPEC = "/meet_up.xml";
	public static String PATH_TICKETOFFICE_SPEC = "/ticket_office.xml";
	public static String PATH_TRANSACTION_SPEC = "/transaction.xml";

	public static String PATH_PERSONALIZED_SPEC = "/personals/";
	
	public static String Q_MECHANISM = "mechanism";
	public static String Q_NAME = "name";
	public static String Q_OPERATION = "operation";
	public static String Q_MSGTEXT = "msgText";
	public static String Q_NMBR = "nmbr";
	
	public static String VALUE_CREATE = "create";
	public static String VALUE_DELETE = "delete";
	public static String VALUE_ACQUIRE = "acquire";
	public static String VALUE_RELEASE = "release";
	public static String VALUE_GETMSG = "getMsg";
	public static String VALUE_PUTMSG = "putMsg";
	public static String VALUE_TAKENMBR = "takeNmbr";
	public static String VALUE_BYE = "bye";
	public static String VALUE_HELLO = "hello";
	public static String VALUE_GETCOUNT = "getCount";
	public SyncREST(){
	}
	
	private Repository repository = null;
	private InstanceManager mngInstance = null;
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
		try {
			String result;
			if (repository == null) {
				repository = new Repository();
			}
			mngInstance = InstanceManager.getInstanceManager();			

			//Get Blank specification
			String additionalPath = req.getPathInfo();
			if (additionalPath != null) {
				if (additionalPath.equals(PATH_TICKETOFFICE_SPEC) ||
						additionalPath.equals(PATH_MEETUP_SPEC) ||	
						additionalPath.equals(PATH_TRANSACTION_SPEC)) {		 
					result = repository.getBlankSpec(additionalPath);
					respondToClient(resp, result);
					return;
				} else {
					//Get Personalized specification
					if (additionalPath.startsWith(PATH_PERSONALIZED_SPEC)){
						String personalKey = additionalPath.substring(PATH_PERSONALIZED_SPEC.length());
						result = repository.getSpec(personalKey);
						respondToClient(resp, result);
						return;
					}
				}

			}			

			//Get Personalized data in JSON --> POST
			//take unique identifier for addressing data

			//Save Personalized specification
			//to generate personalized user ID in repository path
			UUID personalizedUserID = UUID.randomUUID(); 

			//Rename specification --> POST

			//TODO --> POST 

			//Create instance
			String user = "fakeCookie";
 			String mechanism = req.getParameter(Q_MECHANISM);
			String name = req.getParameter(Q_NAME);
			String operation = req.getParameter(Q_OPERATION);
			String msgText = req.getParameter(Q_MSGTEXT);
			String nmbr = req.getParameter(Q_NMBR);
			
			if (!isValidMechanism(mechanism)){
				respondToClient(resp, "You specified an invaild mechanism!");
				return;
			}
			if (!isValidOperation(mechanism, operation)){
				respondToClient(resp, "You specified an invaild operation on the mechanism!");
				return;
			}
				
			
			if (operation.equals(VALUE_CREATE)){
				result = mngInstance.addNew("/" + user + "~" + mechanism + "~" + name, 
						mechanism);
				respondToClient(resp, result);
			} else //Delete instance			
			if (operation.equals(VALUE_DELETE)){
				//TODO check if name begins with "/" + user + "~" + mechanism + "~" + name
				//This lacks authorization, and the key for deleting is fishy 
				//I think delete dos not work properly
				    result = mngInstance.delete(user + "~" + mechanism + "~" + name);
				    respondToClient(resp, result);
				
			} else //Acquire 
			if (operation.equals(VALUE_ACQUIRE)){
				result = mngInstance.acquire(name, 
						user, mechanism);
				respondToClient(resp, result);
			} else //Release instance
			if (operation.equals(VALUE_RELEASE)){
				result = mngInstance.release(name, 
						user, mechanism);
				respondToClient(resp, result);
			} else 
			if (operation.equals(VALUE_PUTMSG)){
				result = mngInstance.putMsg(name, 
						user, msgText);
				respondToClient(resp, result);
			} else 
			if (operation.equals(VALUE_GETMSG)){
				result = mngInstance.getMsg(name, 
						user);
				respondToClient(resp, result);
			} else 
			if (operation.equals(VALUE_TAKENMBR)){
				result = mngInstance.takeNmbr(name, 
						user);
				respondToClient(resp, result);
			} else
			if (operation.equals(VALUE_BYE)){
				result = mngInstance.bye(name, 
						user);
				respondToClient(resp, result);
			} else
			if (operation.equals(VALUE_HELLO)){
				result = mngInstance.hello(name, 
						user, nmbr);
				respondToClient(resp, result);
			} else
			if (operation.equals(VALUE_GETCOUNT)){
				result = mngInstance.getCounter(name, 
						user);
				respondToClient(resp, result);
			}
			

		} catch (Exception err){
			respondToClient(resp, err.getMessage());
		}
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
		try {
			String result = "";
			String user = "fakeCookie";
 			String mechanism = req.getParameter(Q_MECHANISM);
			String name = req.getParameter(Q_NAME);
			String operation = req.getParameter(Q_OPERATION);
			String msgText = req.getParameter(Q_MSGTEXT);
			String nmbr = req.getParameter(Q_NMBR);
			
			if (!isValidMechanism(mechanism)){
				respondToClient(resp, "You specified an invaild mechanism!");
				return;
			}
			if (!isValidOperation(mechanism, operation)){
				respondToClient(resp, "You specified an invaild operation on the mechanism!");
				return;
			}
				
			
			if (operation.equals(VALUE_CREATE)){
				result = mngInstance.addNew("/" + user + "~" + mechanism + "~" + name, 
						mechanism);
				respondToClient(resp, result);
			} else //Delete instance			
			if (operation.equals(VALUE_DELETE)){
				//TODO check if name begins with "/" + user + "~" + mechanism + "~" + name
				//This lacks authorization, and the key for deleting is fishy 
				//I think delete dos not work properly
				    result = mngInstance.delete(user + "~" + mechanism + "~" + name);
				    respondToClient(resp, result);
				
			} else //Acquire 
			if (operation.equals(VALUE_ACQUIRE)){
				result = mngInstance.acquire(name, 
						user, mechanism);
				respondToClient(resp, result);
			} else //Release instance
			if (operation.equals(VALUE_RELEASE)){
				result = mngInstance.release(name, 
						user, mechanism);
				respondToClient(resp, result);
			} else 
			if (operation.equals(VALUE_PUTMSG)){
				result = mngInstance.putMsg(name, 
						user, msgText);
				respondToClient(resp, result);
			} else 
			if (operation.equals(VALUE_GETMSG)){
				result = mngInstance.getMsg(name, 
						user);
				respondToClient(resp, result);
			} else 
			if (operation.equals(VALUE_TAKENMBR)){
				result = mngInstance.takeNmbr(name, 
						user);
				respondToClient(resp, result);
			} else
			if (operation.equals(VALUE_BYE)){
				result = mngInstance.bye(name, 
						user);
				respondToClient(resp, result);
			} else
			if (operation.equals(VALUE_HELLO)){
				result = mngInstance.hello(name, 
						user, nmbr);
				respondToClient(resp, result);
			}else
			if (operation.equals(VALUE_GETCOUNT)){
				result = mngInstance.getCounter(name, 
						user);
				respondToClient(resp, result);
			}			
			
		} catch (Exception err){
			respondToClient(resp, err.getMessage());
		}
	}

	
	private void respondToClient(HttpServletResponse resp, String response) throws IOException {
		try {
			resp.getWriter().print(response);
		} catch (Exception err) {
			resp.getWriter().print(err.getMessage());
		}
	};

	/* Example of usage
	 	Cookie[] cookies = req.getCookies();
		if (cookies != null) {
			userId = getUserIdFromCookies(cookies);	
		}
	 */
	private String getUserIdFromCookies(Cookie [] cookies) {

		for(int i = 0; i < cookies.length; i++) {
			Cookie cookie = cookies[i];
			String cookieName = cookie.getName();
			if (cookieName.equals("moj_kuki")){
				return cookie.getValue();
			}
		}
		return null;
	}
	
	private boolean isValidMechanism(String mechanism){
		boolean result =  false;
		String [] listOfMechanisms = {"semaphore", "mailbox", "token"};
		for (int i = 0; i < listOfMechanisms.length; i++){
			if (mechanism.equals(listOfMechanisms[i])){
				result = true;
				break;
			}
		}		
		return result;
	}

	private boolean isValidOperation(String mechanism, String operation){
		boolean result =  false;
		Hashtable mech_operations = new Hashtable();		
		mech_operations.put("semaphore", new String[] {"create", "delete", "acquire", "release"});
		mech_operations.put("mailbox", new String[] {"create", "delete", "getMsg", "putMsg"});
		mech_operations.put("token", new String[] {"create", "delete", "takeNmbr", "bye", "hello", "getCount"});
		try {
			String [] oper = (String []) mech_operations.get(mechanism);
			for (int i = 0; i < oper.length; i++){
				if (operation.equals(oper[i])){
					result = true;
					break;
				}
			}			
			return result;
		} catch (Exception ex) {
			return false;
		}
	}
	
}
